// Description: 描述
package tools

import (
	"bytes"
	"crypto/des"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/bcrypt"
)

func Base64Encode(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

func Base64Decode(data string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(data)
}

func Base64URLEncode(data []byte) string {
	return base64.RawURLEncoding.EncodeToString(data)
}

func Base64URLDecode(data string) ([]byte, error) {
	return base64.RawURLEncoding.DecodeString(data)
}

// MD5 对字符串进行MD5加密
func MD5(str string) string {
	hash := md5.New()
	hash.Write([]byte(str))
	return hex.EncodeToString(hash.Sum([]byte("")))
}

func MD5to16(str string) string {
	return MD5(str)[8:24]
}

// Sha1 对字符串进行Sha1加密
func Sha1(str string) string {
	hash := sha1.New()
	hash.Write([]byte(str))
	return hex.EncodeToString(hash.Sum([]byte("")))
}

// Hmac 对值进行Hmac加密
func Hmac(key, value string) string {
	hash := hmac.New(md5.New, []byte(key))
	hash.Write([]byte(value))
	return hex.EncodeToString(hash.Sum([]byte("")))
}

// EncryptPassword 对密码进行加密处理
func EncryptPassword(password string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}

	return string(hash), nil
}

// ComparePassword 对密码进行比对
func ComparePassword(encryptedPassword string, plaintextPassword string) error {
	return bcrypt.CompareHashAndPassword([]byte(encryptedPassword), []byte(plaintextPassword))
}

func DesEncrypt(plainText []byte, key []byte) ([]byte, error) {
	// block, err := des.NewTripleDESCipher(key)为三重DES加密
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()                     // 分组大小
	plainText = paddingWithPKCS5(plainText, blockSize) // 填充

	var cipherText = make([]byte, len(plainText))

	// ECB每个分组单独加密
	var temp = cipherText
	for len(plainText) > 0 {
		block.Encrypt(temp, plainText[:blockSize])
		plainText = plainText[blockSize:]
		temp = temp[blockSize:]
	}
	return cipherText, nil
}

func DesDecrypt(cipherText []byte, key []byte) ([]byte, error) {
	// block, err := des.NewTripleDESCipher(key)为三重DES加密
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize() // 分组大小
	if !(len(cipherText) > 0 && (len(cipherText)%blockSize == 0)) {
		return nil, errors.New("")
	}

	var plainText = make([]byte, len(cipherText))

	// ECB每个分组单独加密
	var temp = plainText
	for len(cipherText) > 0 {
		block.Decrypt(temp, cipherText[:blockSize])
		cipherText = cipherText[blockSize:]
		temp = temp[blockSize:]
	}
	plainText = unPaddingWithPKCS5(plainText)
	return plainText, nil
}

func paddingWithPKCS5(data []byte, blockSize int) []byte {
	// 需要填充的值以及数量
	padding := blockSize - len(data)%blockSize
	// 组装填充值([]byte)
	var paddingData = []byte{byte(padding)}
	paddingData = bytes.Repeat(paddingData, padding)
	// append填充
	data = append(data, paddingData...)
	return data
}

func unPaddingWithPKCS5(data []byte) []byte {
	padding := int(data[len(data)-1])
	return data[:len(data)-padding]
}
